1   /*
2    * Copyright (C) 2011 The Guava Authors
3    *
4    * Licensed under the Apache License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    *
8    * http://www.apache.org/licenses/LICENSE-2.0
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   */
16  
17  package com.google.common.base;
18  
19  import com.google.common.annotations.GwtCompatible;
20  import com.google.common.annotations.GwtIncompatible;
21  import com.google.common.collect.ImmutableSet;
22  import com.google.common.testing.GcFinalization;
23  import com.google.common.testing.NullPointerTester;
24  import com.google.common.testing.SerializableTester;
25  
26  import junit.framework.TestCase;
27  
28  import java.lang.annotation.Retention;
29  import java.lang.annotation.RetentionPolicy;
30  import java.lang.ref.WeakReference;
31  import java.lang.reflect.Field;
32  import java.net.URLClassLoader;
33  import java.util.HashSet;
34  import java.util.Set;
35  
36  /**
37   * Tests for {@link Enums}.
38   *
39   * @author Steve McKay
40   */
41  @GwtCompatible(emulated = true)
42  public class EnumsTest extends TestCase {
43  
44    private enum TestEnum {
45      CHEETO,
46      HONDA,
47      POODLE,
48    }
49  
50    private enum OtherEnum {}
51  
52    public void testGetIfPresent() {
53      assertEquals(Optional.of(TestEnum.CHEETO), Enums.getIfPresent(TestEnum.class, "CHEETO"));
54      assertEquals(Optional.of(TestEnum.HONDA), Enums.getIfPresent(TestEnum.class, "HONDA"));
55      assertEquals(Optional.of(TestEnum.POODLE), Enums.getIfPresent(TestEnum.class, "POODLE"));
56  
57      assertTrue(Enums.getIfPresent(TestEnum.class, "CHEETO").isPresent());
58      assertTrue(Enums.getIfPresent(TestEnum.class, "HONDA").isPresent());
59      assertTrue(Enums.getIfPresent(TestEnum.class, "POODLE").isPresent());
60  
61      assertEquals(TestEnum.CHEETO, Enums.getIfPresent(TestEnum.class, "CHEETO").get());
62      assertEquals(TestEnum.HONDA, Enums.getIfPresent(TestEnum.class, "HONDA").get());
63      assertEquals(TestEnum.POODLE, Enums.getIfPresent(TestEnum.class, "POODLE").get());
64    }
65  
66    public void testGetIfPresent_caseSensitive() {
67      assertFalse(Enums.getIfPresent(TestEnum.class, "cHEETO").isPresent());
68      assertFalse(Enums.getIfPresent(TestEnum.class, "Honda").isPresent());
69      assertFalse(Enums.getIfPresent(TestEnum.class, "poodlE").isPresent());
70    }
71  
72    public void testGetIfPresent_whenNoMatchingConstant() {
73      assertEquals(Optional.absent(), Enums.getIfPresent(TestEnum.class, "WOMBAT"));
74    }
75  
76    @GwtIncompatible("weak references")
77    public void testGetIfPresent_doesNotPreventClassUnloading() throws Exception {
78      WeakReference<?> shadowLoaderReference = doTestClassUnloading();
79      GcFinalization.awaitClear(shadowLoaderReference);
80    }
81  
82    // Create a second ClassLoader and use it to get a second version of the TestEnum class.
83    // Run Enums.getIfPresent on that other TestEnum and then return a WeakReference containing the
84    // new ClassLoader. If Enums.getIfPresent does caching that prevents the shadow TestEnum
85    // (and therefore its ClassLoader) from being unloaded, then this WeakReference will never be
86    // cleared.
87    @GwtIncompatible("weak references")
88    private WeakReference<?> doTestClassUnloading() throws Exception {
89      URLClassLoader myLoader = (URLClassLoader) getClass().getClassLoader();
90      URLClassLoader shadowLoader = new URLClassLoader(myLoader.getURLs(), null);
91      @SuppressWarnings("unchecked")
92      Class<TestEnum> shadowTestEnum =
93          (Class<TestEnum>) Class.forName(TestEnum.class.getName(), false, shadowLoader);
94      assertNotSame(shadowTestEnum, TestEnum.class);
95      Set<TestEnum> shadowConstants = new HashSet<TestEnum>();
96      for (TestEnum constant : TestEnum.values()) {
97        Optional<TestEnum> result = Enums.getIfPresent(shadowTestEnum, constant.name());
98        assertTrue(result.isPresent());
99        shadowConstants.add(result.get());
100     }
101     assertEquals(ImmutableSet.copyOf(shadowTestEnum.getEnumConstants()), shadowConstants);
102     Optional<TestEnum> result = Enums.getIfPresent(shadowTestEnum, "blibby");
103     assertFalse(result.isPresent());
104     return new WeakReference<ClassLoader>(shadowLoader);
105   }
106 
107   public void testStringConverter_convert() {
108     Converter<String, TestEnum> converter = Enums.stringConverter(TestEnum.class);
109     assertEquals(TestEnum.CHEETO, converter.convert("CHEETO"));
110     assertEquals(TestEnum.HONDA, converter.convert("HONDA"));
111     assertEquals(TestEnum.POODLE, converter.convert("POODLE"));
112     assertNull(converter.convert(null));
113     assertNull(converter.reverse().convert(null));
114   }
115 
116   public void testStringConverter_convertError() {
117     Converter<String, TestEnum> converter = Enums.stringConverter(TestEnum.class);
118     try {
119       converter.convert("xxx");
120       fail();
121     } catch (IllegalArgumentException expected) {
122     }
123   }
124 
125   public void testStringConverter_reverse() {
126     Converter<String, TestEnum> converter = Enums.stringConverter(TestEnum.class);
127     assertEquals("CHEETO", converter.reverse().convert(TestEnum.CHEETO));
128     assertEquals("HONDA", converter.reverse().convert(TestEnum.HONDA));
129     assertEquals("POODLE", converter.reverse().convert(TestEnum.POODLE));
130   }
131 
132   @GwtIncompatible("NullPointerTester")
133   public void testStringConverter_nullPointerTester() throws Exception {
134     Converter<String, TestEnum> converter = Enums.stringConverter(TestEnum.class);
135     NullPointerTester tester = new NullPointerTester();
136     tester.testAllPublicInstanceMethods(converter);
137   }
138 
139   public void testStringConverter_nullConversions() {
140     Converter<String, TestEnum> converter = Enums.stringConverter(TestEnum.class);
141     assertNull(converter.convert(null));
142     assertNull(converter.reverse().convert(null));
143   }
144 
145   @GwtIncompatible("Class.getName()")
146   public void testStringConverter_toString() {
147     assertEquals(
148         "Enums.stringConverter(com.google.common.base.EnumsTest$TestEnum.class)",
149         Enums.stringConverter(TestEnum.class).toString());
150   }
151 
152   public void testStringConverter_serialization() {
153     SerializableTester.reserializeAndAssert(Enums.stringConverter(TestEnum.class));
154   }
155 
156   @GwtIncompatible("NullPointerTester")
157   public void testNullPointerExceptions() {
158     NullPointerTester tester = new NullPointerTester();
159     tester.testAllPublicStaticMethods(Enums.class);
160   }
161 
162   @Retention(RetentionPolicy.RUNTIME)
163   private @interface ExampleAnnotation {}
164 
165   private enum AnEnum {
166     @ExampleAnnotation FOO,
167     BAR
168   }
169 
170   @GwtIncompatible("reflection")
171   public void testGetField() {
172     Field foo = Enums.getField(AnEnum.FOO);
173     assertEquals("FOO", foo.getName());
174     assertTrue(foo.isAnnotationPresent(ExampleAnnotation.class));
175 
176     Field bar = Enums.getField(AnEnum.BAR);
177     assertEquals("BAR", bar.getName());
178     assertFalse(bar.isAnnotationPresent(ExampleAnnotation.class));
179   }
180 }